/**
 ***************************************************************************************************
 *
 * @file app.c
 *
 * @brief Application entry point
 *
 * Copyright (C) Eker 2021
 *
 ***************************************************************************************************
 */

/**
 ***************************************************************************************************
 * @addtogroup APP
 * @{
 ***************************************************************************************************
 */

/*
 * INCLUDE FILES
 ***************************************************************************************************
 */
#include "app.h"

#define APP_LOG_DOMAIN      "app"
#define APP_LOG_LEVEL       APP_LOG_LEVEL_APP
#include "app_log.h"

/*
 * DEFINES
 ***************************************************************************************************
 */

/*
 * TYPE DEFINITIONS
 ***************************************************************************************************
 */
typedef void (*appm_add_svc_func_t)(void);

/*
 * ENUMERATIONS
 ***************************************************************************************************
 */
// List of service to add in the database
enum appm_svc_list
{
    APPM_SVC_TSPP_SERVER,

    APPM_SVC_LIST_STOP,
};

/*
 * LOCAL VARIABLES DEFINITIONS
 ***************************************************************************************************
 */
// Application Task Descriptor
extern const struct ke_task_desc TASK_DESC_APP;

// List of functions used to create the database
static const appm_add_svc_func_t appm_add_svc_func_list[APPM_SVC_LIST_STOP] =
{
    (appm_add_svc_func_t)app_ty_server_add_service,
};

/*
 * GLOBAL VARIABLE DEFINITIONS
 ***************************************************************************************************
 */
// Application Environment Structure
struct app_env_tag app_env;

/*
 * LOCAL FUNCTION DEFINITIONS
 ***************************************************************************************************
 */
static void appm_send_gapm_reset_cmd(void)
{
    // Reset the stack
    struct gapm_reset_cmd *p_cmd = KE_MSG_ALLOC(GAPM_RESET_CMD,
                                                TASK_GAPM, TASK_APP,
                                                gapm_reset_cmd);

    p_cmd->operation = GAPM_RESET;

    ke_msg_send(p_cmd);
}

/*
 * GLOBAL FUNCTION DEFINITIONS
 ***************************************************************************************************
 */
void appm_reg_svc_itf(void)
{
    struct prf_itf_pair itf_pair[] = {
        { TASK_ID_TYS, ty_server_prf_itf_get() },
    };
    prf_itf_register(itf_pair, sizeof(itf_pair)/sizeof(itf_pair[0]));
}

bool appm_add_svc(void)
{
    // Indicate if more services need to be added in the database
    bool more_svc = false;

    // Check if another should be added in the database
    if (app_env.next_svc != APPM_SVC_LIST_STOP)
    {
        ASSERT_INFO(appm_add_svc_func_list[app_env.next_svc] != NULL, app_env.next_svc, 1);

        // Call the function used to add the required service
        appm_add_svc_func_list[app_env.next_svc]();

        // Select following service to add
        app_env.next_svc++;
        more_svc = true;

        // Go to the create db state
        ke_state_set(TASK_APP, APPM_CREATE_DB);
    }

    return more_svc;
}

void appm_disconnect(uint8_t conidx, uint8_t reason)
{
    struct gapc_disconnect_cmd *cmd = KE_MSG_ALLOC(GAPC_DISCONNECT_CMD,
                                                   KE_BUILD_ID(TASK_GAPC, conidx),
                                                   KE_BUILD_ID(TASK_APP, conidx),
                                                   gapc_disconnect_cmd);

    cmd->operation = GAPC_DISCONNECT;
    cmd->reason = reason;

    // Send the message
    ke_msg_send(cmd);
}

void appm_update_param(uint8_t conidx, struct gapc_conn_param * conn_param)
{
    // Prepare the GAPC_PARAM_UPDATE_CMD message
    struct gapc_param_update_cmd *cmd = KE_MSG_ALLOC(GAPC_PARAM_UPDATE_CMD,
                                                     KE_BUILD_ID(TASK_GAPC, conidx),
                                                     KE_BUILD_ID(TASK_APP, conidx),
                                                     gapc_param_update_cmd);

    cmd->operation  = GAPC_UPDATE_PARAMS;
    cmd->intv_min   = conn_param->intv_min;
    cmd->intv_max   = conn_param->intv_max;
    cmd->latency    = conn_param->latency;
    cmd->time_out   = conn_param->time_out;

    // not used by a slave device
    cmd->ce_len_min = 0xFFFF;
    cmd->ce_len_max = 0xFFFF;

    // Send the message
    ke_msg_send(cmd);
}

#if(BLE_APP_SEC)
/**
 ***************************************************************************************************
 * @brief Set local irk
 *
 * @param[void]
 *
 * @return void
 ***************************************************************************************************
 */
void app_gap_set_local_irk(void)
{
     uint8_t key_len = KEY_LEN;
    if (app_sec_get_bond_status()==true)
    {
    #if (NVDS_SUPPORT)
        // If Bonded retrieve the local IRK from NVDS
        if (nvds_get(NVDS_TAG_LOC_IRK, &key_len, app_env.loc_irk) == NVDS_OK)
        {
            // Set the IRK in the GAP
            struct gapm_set_irk_cmd *cmd = KE_MSG_ALLOC(GAPM_SET_IRK_CMD,
                                                        TASK_GAPM, TASK_APP,
                                                        gapm_set_irk_cmd);
            cmd->operation = GAPM_SET_IRK;
            memcpy(&cmd->irk.key[0], &app_env.loc_irk[0], KEY_LEN);
            ke_msg_send(cmd);
        }
    #endif
    }
    else // Need to start the generation of new IRK
    {
        struct gapm_gen_rand_nb_cmd *cmd = KE_MSG_ALLOC(GAPM_GEN_RAND_NB_CMD,
                                                        TASK_GAPM, TASK_APP,
                                                        gapm_gen_rand_nb_cmd);
        cmd->operation   = GAPM_GEN_RAND_NB;
        app_env.rand_cnt = 1;
        ke_msg_send(cmd);
    }
}
#endif
